package fnic.modesearch;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;

import fnic.jsontrans.SearchResultJsonMode.*;

public class SearchModeJsonGenerater {
	private static final ObjectMapper mapper = new ObjectMapper();
	private static final Logger LOG = Logger.getLogger(SearchModeJsonGenerater.class);
	private static final JsonFactory f = new JsonFactory();
	
	SearchModeJsonParser parser;
	
	// 响应输出json构造对象
	JsonGenerator jsonGenerator = null;
	JsonGenerator bulkGenerator = null;
	ByteArrayOutputStream bulkstream = null;
	ByteArrayOutputStream resultstream = null;
	ByteArrayOutputStream statstream = null;
	
	public long totalhits;
	public List<Map<String, Object>> hitsoutput = null;
	public List<TypeScore>  ranking = null;
	public OutTermFieldStat[] outtermStat = null;
	public OutTermsKVStat[]  outkvsStat = null;
	public OutFieldStat[] outfieldStat = null;
	public OutRangesGroupStat[] outrangegroupsStat = null;
	
	/* 统计字段                                                       <possition      >=position
	 * pingdelayavg,           150,          150
	 * downlink.avg_speed,     100,          200
	 * uplink.avg_speed,       10,           290
	 */
	Map<String, Long[]> rankmap = null;
	
	
	public SearchModeJsonGenerater(){
		bulkstream = new ByteArrayOutputStream();
		resultstream = new ByteArrayOutputStream();
		statstream = new ByteArrayOutputStream();
		try {
			bulkGenerator  = f.createJsonGenerator(bulkstream, JsonEncoding.UTF8);
			jsonGenerator = f.createJsonGenerator(resultstream, JsonEncoding.UTF8);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			LOG.error(e.getMessage());
		}
	}
	
	public void close(){
		try {
			if(bulkGenerator!=null)  bulkGenerator.close();
			if(jsonGenerator!=null)  jsonGenerator.close();
			
			if(bulkstream!=null)  bulkstream.close();
			if(resultstream!=null)  resultstream.close();
			if(statstream!=null)  statstream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void setParser(SearchModeJsonParser parser){
		this.parser = parser;
	}
	
	public long getTotalhits() {
		return totalhits;
	}
	public List<Map<String, Object>> getHitsoutput() {
		return hitsoutput;
	}
	public OutTermFieldStat[] getOuttermStat() {
		return outtermStat;
	}
	public OutTermsKVStat[] getOutkvsStat() {
		return outkvsStat;
	}
	public OutFieldStat[] getOutfieldStat() {
		return outfieldStat;
	}
	public OutRangesGroupStat[] getOutrangegroupsStat() {
		return outrangegroupsStat;
	}
	
	public void setTotalhits(long totalhits) {
		this.totalhits = totalhits;
	}
	
	public String jsonOut(){	
		try {
			jsonGenerator.writeStartObject();                           //{
			
			if(parser.isTotalflg()){
				jsonGenerator.writeNumberField("totalhits", totalhits); //"totalhits":1
			}
			
			if(parser.isKeyflg()){
				jsonGenerator.writeStringField("key", parser.getKey());
			}
			
			if(parser.isRankingflg()){
				int s = caculateScore();
				for(TypeScore score: ranking){
					score.setScore(s);
				}
				jsonGenerator.writeFieldName("ranking");
				mapper.writeValue(statstream, ranking);
				jsonGenerator.writeRawValue(statstream.toString());
				statstream.reset();
			}
			
			if(parser.isOutputflg()){                                   //"output":[]
				mapper.writeValue(statstream, hitsoutput);
				jsonGenerator.writeFieldName("output");
				jsonGenerator.writeRawValue(statstream.toString());
				statstream.reset();
			}
			
			if(parser.isStatflg()){
				jsonGenerator.writeArrayFieldStart("statistic");      //"statistic":[
				
				if(outtermStat!=null){                                //"type": "termstat", "result":
					jsonGenerator.writeStartObject();                
					jsonGenerator.writeStringField("type", "termstat");
					jsonGenerator.writeFieldName("result");
					mapper.writeValue(statstream, outtermStat);
					jsonGenerator.writeRawValue(statstream.toString());
					jsonGenerator.writeEndObject();
					statstream.reset();
				}
				if(outkvsStat!=null){                                 //"type": "kvstat", "result":
					jsonGenerator.writeStartObject();
					jsonGenerator.writeStringField("type", "kvstat");
					jsonGenerator.writeFieldName("result");
					mapper.writeValue(statstream, outkvsStat);
					jsonGenerator.writeRawValue(statstream.toString());
					jsonGenerator.writeEndObject();
					statstream.reset();
				}
				if(outfieldStat!=null){                              //"type": "fieldstat", "result":
					jsonGenerator.writeStartObject();
					jsonGenerator.writeStringField("type", "fieldstat");
					jsonGenerator.writeFieldName("result");
					mapper.writeValue(statstream, outfieldStat);
					jsonGenerator.writeRawValue(statstream.toString());
					jsonGenerator.writeEndObject();
					statstream.reset();
				}
				if(outrangegroupsStat!=null){                         //"type": "rangestat", "result":
					jsonGenerator.writeStartObject();
					jsonGenerator.writeStringField("type", "rangestat");
					jsonGenerator.writeFieldName("result");
					mapper.writeValue(statstream, outrangegroupsStat);
					jsonGenerator.writeRawValue(statstream.toString());
					jsonGenerator.writeEndObject();
					statstream.reset();
				}
				
				jsonGenerator.writeEndArray();           //"statistic"  ]
			}
			jsonGenerator.writeEndObject();               //}
			
			jsonGenerator.flush();
			String jsonres = resultstream.toString();
			resultstream.reset();
			
//			LOG.info("result:"+jsonres);
			return jsonres;
		} catch (JsonGenerationException e) {
			LOG.error("jsonOut error:"+e.getMessage());
			return null;
		} catch (IOException e) {
			LOG.error("jsonOut error:"+e.getMessage());
			return null;
		}
	}
	
	public boolean startbulkjson(){
		try {
			bulkGenerator.writeStartArray();
		} catch (JsonGenerationException e) {
			LOG.error("startbulkjson error:"+e.getMessage());
			return false;
		} catch (IOException e) {
			LOG.error("startbulkjson error:"+e.getMessage());
			return false;
		}
		return true;
	}
	
	public boolean endbulkjson(){
		try {
			bulkGenerator.writeEndArray();
		} catch (JsonGenerationException e) {
			LOG.error("endbulkjson error:"+e.getMessage());
			return false;
		} catch (IOException e) {
			LOG.error("endbulkjson error:"+e.getMessage());
			return false;
		}
		return true;
	}
	
	public boolean bulkjsonitem(){
		try {
			bulkGenerator.writeRawValue(jsonOut());
		} catch (JsonGenerationException e) {
			LOG.error("bulkjsonitem error:"+e.getMessage());
			return false;
		} catch (IOException e) {
			LOG.error("bulkjsonitem error:"+e.getMessage());
			return false;
		}
		return true;
	}
	
	public String bulkjsonOut(){
		String facetResult = null;
		try {
			bulkGenerator.flush();
		} catch (IOException e) {
			LOG.error("bulkjsonOut error:"+e.getMessage());
		}
		facetResult = bulkstream.toString();
		bulkstream.reset();
		LOG.info("facets result:" + facetResult);
		return facetResult;
	}
	
	/*
	 * 根据parse的List<TypeScore>和执行完毕的OutRangesGroupStat[]进行评分
	 */
	private int caculateScore(){
		if(!constructRankMap()){
			return 0;
		}
		
		long ping_pos=0;
		long upband_pos = 0;
		long downband_pos = 0;
		int n=0;
		
		if(rankmap.get("ping.mean_rtt_ms")!=null){
			ping_pos = rankmap.get("ping.mean_rtt_ms")[0];
			n++;
		}
		if(rankmap.get("uplink.avg_speed")!=null){
			upband_pos = rankmap.get("uplink.avg_speed")[1];
			n++;
		}
		if(rankmap.get("downlink.avg_speed")!=null){
			downband_pos = rankmap.get("downlink.avg_speed")[1];
			n++;
		}
		
		int all_pos = (int)(ping_pos+upband_pos+downband_pos)/n;
		return all_pos;
	}
	
	private boolean constructRankMap(){
		if(outrangegroupsStat == null){
			return false;
		}
		
		rankmap = new HashMap<String, Long[]>();
		for(OutRangesGroupStat rangeItem : outrangegroupsStat){
			List<Map<String, Double>> ranges = rangeItem.getResobj();
			Long[] count_elements = new Long[ranges.size()];
			int n=0;
			for(Map<String, Double> statelement : ranges){
				if(statelement.get("count")!=null){
					double c = statelement.get("count");
//					if(c<0.1){
//						count_elements[n] = new Long(0);
//					}
//					else{
						count_elements[n++] = new Long((long)c);
//					}
				}else{
//					count_elements[n++] = 0;
					return false;
				}
			}
			rankmap.put(rangeItem.getName(), count_elements);
		}
		
		return true;
	}
}
